/*
 * Project: Sudoku Hint Engine for Android
 * Copyright (C) 2010-2013 Emanuel Moecklin
 * 
 * Available under the terms of the Lesser General Public License (LGPL)
 */
package com.onegravity.sudoku.solver.rules.wing;

import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import android.net.Uri;

import com.onegravity.sudoku.solver.HintResource;
import com.onegravity.sudoku.solver.HintType;
import com.onegravity.sudoku.solver.R;
import com.onegravity.sudoku.solver.core.IndirectHint;
import com.onegravity.sudoku.solver.core.Rule;
import com.onegravity.sudoku.solver.data.Cell;
import com.onegravity.sudoku.solver.data.ImmutableCell;
import com.onegravity.sudoku.solver.data.Region;
import com.onegravity.sudoku.solver.util.BitSetFactory;
import com.onegravity.sudoku.solver.util.HtmlLoader;
import com.onegravity.sudoku.solver.util.Link;

/**
 * W-Wing hints
 * @author Emanuel Moecklin
 */
public class WWingHint extends IndirectHint implements Rule {

	private static final long serialVersionUID = 2849078683155611034L;
	
    private final Cell cellA;
    private final Cell cellB;
    private final Cell cellC;
    private final Cell cellD;
    private final int w;
    private final int x;
    private final Region region;

	public WWingHint(Cell cellA, Cell cellB, Cell cellC, Cell cellD, int w, int x, Region region, Map<Cell,BitSet> removablePotentials) {
        super(removablePotentials);
        this.cellA = cellA;
        this.cellB = cellB;
        this.cellC = cellC;
        this.cellD = cellD;
        this.w = w;
        this.x = x;
        this.region = region;
    }

    @Override
    public Region[] getRegions(HintType hintType) {
    	if (hintType!=HintType.HINT) return null;
        return new Region[] {region};
    }

    @Override
    public Collection<Cell> getSelectedCells(HintType hintType) {
    	if (hintType!=HintType.HINT) {
			ArrayList<Cell> cells = new ArrayList<Cell>();
			cells.add(cellC);
			cells.add(cellB);
			return cells;
		}
		return Collections.emptyList();
    }

    @Override
    public Map<Cell, BitSet> getSelectedPotentials(HintType hintType, int viewNum) {
    	if (hintType!=HintType.HINT) return null;
        Map<Cell, BitSet> result = new HashMap<Cell, BitSet>();
        BitSet wSet = BitSetFactory.createOneElement(w);
        result.put(cellA, wSet);
        result.put(cellD, wSet);
    	return result;
    }

    @Override
    public Map<Cell, BitSet> getAddedPotentials(HintType hintType, int viewNum) {
    	if (hintType==HintType.SMALL_CLUE) return null;
        Map<Cell, BitSet> result = new HashMap<Cell, BitSet>();
        BitSet xSet = BitSetFactory.createOneElement(x);
        result.put(cellA, xSet);
        result.put(cellC, xSet);
    	return result;
    }
    
    @Override
    public Map<Cell, BitSet> getSecondarySelectedPotentials(HintType hintType, int viewNum) {
    	if (hintType==HintType.SMALL_CLUE) return null;
        Map<Cell, BitSet> result = new HashMap<Cell, BitSet>();
        BitSet xSet = BitSetFactory.createOneElement(x);
        result.put(cellB, xSet);
        result.put(cellD, xSet);
    	return result;
    }

    @Override
    public Map<ImmutableCell, BitSet> getRemovedPotentials(HintType hintType) {
        return (hintType==HintType.HINT) ? super.getRemovedPotentials(hintType) : null;
    }

    @Override
    public Collection<Link> getLinks(HintType hintType, int viewNum) {
        if (hintType!=HintType.HINT) return null;
        Collection<Link> result = new ArrayList<Link>();
        result.add( new Link(cellA, x, cellB, x) );
        result.add( new Link(cellB, x, cellC, x) );
        result.add( new Link(cellC, x, cellD, x) );
    	return result;
    }

    @Override
    public double getDifficulty() {
    	return 4.4;
    }

    @Override
    public String getName() {
    	return HintResource.WWING.getName();
    }

    @Override
    public Uri getLink() {
    	return HintResource.WWING.getUrl();
	}

    @Override
    public boolean equals(Object o) {
        if (!(o instanceof WWingHint)) return false;
        WWingHint other = (WWingHint)o;
        if (!this.cellA.equals(other.cellA)) return false;
        if (!this.cellB.equals(other.cellB)) return false;
        if (!this.cellC.equals(other.cellC)) return false;
        if (!this.cellD.equals(other.cellD)) return false;
        if (this.w != other.w) return false;
        if (this.x != other.x) return false;
        return true;
    }

    @Override
    public int hashCode() {
    	int hash = x+w;
   		hash ^= cellA.hashCode();
   		hash ^= cellB.hashCode();
   		hash ^= cellC.hashCode();
   		hash ^= cellD.hashCode();
        return hash;
    }

    @Override
    public String getHintHtml(HintType hintType) {
    	HintResource hintRes = HintResource.WWING;
        String result = HtmlLoader.loadHtml(hintRes.hint(hintType));
        return HtmlLoader.format(result, cellA.toString(), cellB.toString(), cellC.toString(), cellD.toString(), w, x, region.toFullString());
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append(getName());
        builder.append(": "); //$NON-NLS-1$
        builder.append(cellA.toString());
        builder.append(cellB.toString());
        builder.append(cellC.toString());
        builder.append(cellD.toString());
        builder.append(HintResource.getString(R.string.hint_wwing_onvalue));
        builder.append(w + "/" + x); //$NON-NLS-1$
        return builder.toString();
    }

    @Override
    public int getNrOfSteps() {
        return 3;
    }

}